/* * Sun Public License Notice * * The contents of this file are subject to the Sun Public License * Version 1.0 (the "License"). You may not use this file except in * compliance with the License. A copy of the License is available at * http://www.sun.com/ * * The Original Code is Forte for Java, Community Edition. The Initial * Developer of the Original Code is Sun Microsystems, Inc. Portions * Copyright 1997-2000 Sun Microsystems, Inc. All Rights Reserved. */ package org.openide.src; import java.util.StringTokenizer; import java.util.HashMap; import java.lang.ref.WeakReference; import java.io.Serializable; import org.openide.util.Utilities; /** Java types. * * @author Petr Hamernik, Ian Formanek */ public final class Type extends Object implements Cloneable, Serializable { /** Private constants for types */ private static final int T_BOOLEAN = 0x0001; private static final int T_INT = 0x0002; private static final int T_CHAR = 0x0003; private static final int T_BYTE = 0x0004; private static final int T_SHORT = 0x0005; private static final int T_LONG = 0x0006; private static final int T_FLOAT = 0x0007; private static final int T_DOUBLE = 0x0008; private static final int T_VOID = 0x0009; private static final int T_CLASS = 0x0010; private static final int T_ARRAY = 0x0020; private static final int T_PRIMITIVE= 0x000F; /** <code>void</code> primitive type. */ public static final Type VOID = new Type(T_VOID); /** <code>boolean</code> primitive type. */ public static final Type BOOLEAN = new Type(T_BOOLEAN); /** <code>int</code> primitive type. */ public static final Type INT = new Type(T_INT); /** <code>char</code> primitive type. */ public static final Type CHAR = new Type(T_CHAR); /** <code>byte</code> primitive type. */ public static final Type BYTE = new Type(T_BYTE); /** <code>short</code> primitive type. */ public static final Type SHORT = new Type(T_SHORT); /** <code>long</code> primitive type. */ public static final Type LONG = new Type(T_LONG); /** <code>float</code> primitive type. */ public static final Type FLOAT = new Type(T_FLOAT); /** <code>double</code> primitive type. */ public static final Type DOUBLE = new Type(T_DOUBLE); /** Table where strings like "int" are keys and classes like INT are values * @associates Type*/ // NOI18N private static HashMap text2type = new HashMap(); private static final String L_VOID = "void"; // NOI18N private static final String L_BOOLEAN = "boolean"; // NOI18N private static final String L_INT = "int"; // NOI18N private static final String L_CHAR = "char"; // NOI18N private static final String L_BYTE = "byte"; // NOI18N private static final String L_SHORT = "short"; // NOI18N private static final String L_LONG = "long"; // NOI18N private static final String L_FLOAT = "float"; // NOI18N private static final String L_DOUBLE = "double"; // NOI18N private static final String[] PRIMITIVE_NAMES = { L_VOID, L_BOOLEAN, L_INT, L_CHAR, L_BYTE, L_SHORT, L_LONG, L_FLOAT, L_DOUBLE }; static { text2type.put(L_VOID, VOID); text2type.put(L_BOOLEAN, BOOLEAN); text2type.put(L_INT, INT); text2type.put(L_CHAR, CHAR); text2type.put(L_BYTE, BYTE); text2type.put(L_SHORT, SHORT); text2type.put(L_LONG, LONG); text2type.put(L_FLOAT, FLOAT); text2type.put(L_DOUBLE, DOUBLE); } /** Kind of this instance of Type */ private int kind; /** Element type if this type is array */ private Type elementType = null; /** Identifier of the class if this type is ClassType */ private Identifier classType = null; static final long serialVersionUID =8997425134968958367L; /** Constructor for primitive type */ private Type(int kind) { this.kind = kind; } /** Creates array of elements of given type. * @param type the element type */ private Type(Type type) { this.kind = T_ARRAY; elementType = type; } private Type(Identifier id) { this.kind = T_CLASS; classType = id; } private Object readResolve() { switch (kind) { case T_BOOLEAN: return BOOLEAN; case T_INT: return INT; case T_CHAR: return CHAR; case T_BYTE: return BYTE; case T_SHORT: return SHORT; case T_LONG: return LONG; case T_FLOAT: return FLOAT; case T_DOUBLE: return DOUBLE; case T_VOID: return VOID; case T_CLASS: return createClass(classType); case T_ARRAY: return createArray(elementType); default: throw new InternalError(); } } /** Get the Java names of the primitive types. * @return the names */ public static String[] getTypesNames() { return PRIMITIVE_NAMES; } /** Create an array type. * @param elementType the element type * @return the array type */ public static Type createArray (Type elementType) { return new Type(elementType); } /** Create a class type by name. * @param id the class name * @return the class type */ public static Type createClass (Identifier id) { return new Type(id); } /** Create a type from an existing class. * @param cl the class * @return the type */ public static Type createFromClass (Class cl) { if (cl.isArray ()) return createArray (createFromClass (cl.getComponentType ())); else if (cl.isPrimitive ()) { if (Void.TYPE.equals (cl)) return VOID; if (Boolean.TYPE.equals (cl)) return BOOLEAN; if (Integer.TYPE.equals (cl)) return INT; if (Character.TYPE.equals (cl)) return CHAR; if (Byte.TYPE.equals (cl)) return BYTE; if (Short.TYPE.equals (cl)) return SHORT; if (Long.TYPE.equals (cl)) return LONG; if (Float.TYPE.equals (cl)) return FLOAT; if (Double.TYPE.equals (cl)) return DOUBLE; throw new InternalError (); // Unknown primitive type } else return createClass (Identifier.create (cl.getName ())); } /** Create a type from its string representation. * @param text the string representation, e.g. <code>"int[][]"</code>, * <code>"java.awt.Button"</code>, etc. * @return the type * @exception InvalidArgumentException if the text cannot be parsed */ public static Type parse(String text) throws IllegalArgumentException { StringTokenizer tok = new StringTokenizer(text, " []", true); // NOI18N Type type = null; int status = 0; while (tok.hasMoreTokens()) { String token = tok.nextToken(); if (token.equals(" ")) // NOI18N continue; switch (status) { case 0: { type = (Type) text2type.get(token); if (type == null) { StringTokenizer tok2 = new StringTokenizer(token, ".", false); // NOI18N while (tok2.hasMoreTokens()) { if (!Utilities.isJavaIdentifier(tok2.nextToken())) { throw new IllegalArgumentException(); } } type = createClass(Identifier.create (token)); } status = 1; break; } case 1: if (!token.equals("[")) // NOI18N throw new IllegalArgumentException(); status = 2; break; case 2: if (!token.equals("]")) // NOI18N throw new IllegalArgumentException(); type = createArray(type); status = 1; break; } } if (type == null) type = VOID; return type; } /** Test if the type is primitive. * @return <CODE>true</CODE> if so */ public boolean isPrimitive () { return ((kind & T_PRIMITIVE) != 0); } /** Test if the type is an array. * @return <CODE>true</CODE> if so */ public boolean isArray () { return (kind == T_ARRAY); } /** Test if the type is a class or interface. * @return <CODE>true</CODE> if so, <code>false</code> if an array or primitive type */ public boolean isClass () { return (kind == T_CLASS); } /** Get the element type of this array type. * @return the element type * @exception IllegalStateException if this type is not an array type */ public Type getElementType () throws IllegalStateException { if (isArray()) return elementType; else throw new IllegalStateException(); } /** Get the (fully-qualified) name of this class type. * @return the class name * @exception IllegalStateException if this type is not a simple class or interface type */ public Identifier getClassName () throws IllegalStateException { if (isClass()) return classType; else throw new IllegalStateException(); } /** Attempt to get the real class corresponding to this type, using the default class loader. * @return the class * @exception ClassNotFoundException if the class cannot be found */ public Class toClass() throws ClassNotFoundException { return toClass (null); } /** Attempt to get the real class corresponding to this type. * @param loader class loader to use for loading classes * @return the class * @exception ClassNotFoundException if the class cannot be found */ public Class toClass(ClassLoader loader) throws ClassNotFoundException { if (isPrimitive()) { switch (kind) { case T_BOOLEAN : return Boolean.TYPE; case T_INT : return Integer.TYPE; case T_CHAR : return Character.TYPE; case T_BYTE : return Byte.TYPE; case T_SHORT : return Short.TYPE; case T_LONG : return Long.TYPE; case T_FLOAT : return Float.TYPE; case T_DOUBLE : return Double.TYPE; default : return Void.TYPE; //void } } // if no given class loader then use own if (loader == null) { loader = getClass ().getClassLoader (); } if (isClass()) return Class.forName (classType.getFullName(), true, loader); else { // construct array String name = "["; // NOI18N Type t = this; while (t.getElementType ().isArray ()) { name = name + "["; // NOI18N t = t.getElementType (); } if (t.isClass ()) name = name + t.classType.getFullName (); else { switch (t.kind) { case T_BOOLEAN : name = name + "Z"; break; // NOI18N case T_INT : name = name + "I"; break; // NOI18N case T_CHAR : name = name + "C"; break; // NOI18N case T_BYTE : name = name + "B"; break; // NOI18N case T_SHORT : name = name + "S"; break; // NOI18N case T_LONG : name = name + "J"; break; // NOI18N case T_FLOAT : name = name + "F"; break; // NOI18N case T_DOUBLE : name = name + "D"; break; // NOI18N } } return Class.forName (name, true, loader); } } /** Get this type as the string. * @param appendTo The string buffer where to append to * @param source true means getSourceName() will be used, otherwise getFullName() * @return the same string buffer which was passed into */ StringBuffer getAsString(StringBuffer appendTo, boolean source) { if (isPrimitive()) { switch (kind) { case T_BOOLEAN : return appendTo.append("boolean"); // NOI18N case T_INT : return appendTo.append("int"); // NOI18N case T_CHAR : return appendTo.append("char"); // NOI18N case T_BYTE : return appendTo.append("byte"); // NOI18N case T_SHORT : return appendTo.append("short"); // NOI18N case T_LONG : return appendTo.append("long"); // NOI18N case T_FLOAT : return appendTo.append("float"); // NOI18N case T_DOUBLE : return appendTo.append("double"); // NOI18N default : return appendTo.append("void"); //void // NOI18N } } else { if (isClass()) return appendTo.append(source ? classType.getSourceName() : classType.getFullName() ); else { return elementType.getAsString(appendTo, source).append("[]"); // NOI18N } } } /** Get a form of this type usable in Java source. * @return the string representation */ public String getSourceString() { return getAsString(new StringBuffer(), true).toString(); } /** Get a form of this type usable in Java source. * @return the string representation */ public String getFullString() { return getAsString(new StringBuffer(), false).toString(); } /** Get a form of this type usable in Java source. * @return the string representation */ public String toString() { return getSourceString(); } /** Compare the specified Type with this Type for equality. * @param type Type to be compared with this * @param source Determine if the source name (for class types) * should be also compared. * If <CODE>false</CODE> only fully qualified name is compared. * @return <CODE>true</CODE> if the specified object equals to * specified Identifier otherwise <CODE>false</CODE>. */ public boolean compareTo(Type type, boolean source) { if (type.kind != kind) return false; switch (kind) { case T_ARRAY: return type.getElementType().compareTo(getElementType(), source); case T_CLASS: return type.getClassName().compareTo(getClassName(), source); default: return true; } } /** Compare the specified object with this Type for equality. * There are tested only full qualified name if the type is Class * @param o Object to be compared with this * @return <CODE>true</CODE> if the specified object represents the same type * otherwise <CODE>false</CODE>. */ public boolean equals(Object o) { return (o instanceof Type) ? compareTo((Type) o, false) : false; } /** @return the hash code of full name String object. */ public int hashCode() { switch (kind) { case T_ARRAY: return getElementType().hashCode() << 1; case T_CLASS: return getClassName().hashCode(); default: return System.identityHashCode(this); } } } /* * Log * 11 src-jtulach1.10 1/13/00 Petr Hamernik i18n -(2nd round) - * script bug fixed. * 10 src-jtulach1.9 1/12/00 Petr Hamernik i18n using perl script * (//NOI18N comments added) * 9 src-jtulach1.8 10/22/99 Ian Formanek NO SEMANTIC CHANGE - Sun * Microsystems Copyright in File Comment * 8 src-jtulach1.7 8/17/99 Ian Formanek Generated serial version * UID * 7 src-jtulach1.6 6/8/99 Ian Formanek ---- Package Change To * org.openide ---- * 6 src-jtulach1.5 5/13/99 Petr Hamernik * 5 src-jtulach1.4 5/12/99 Petr Hamernik Identifier * implementation updated * 4 src-jtulach1.3 3/30/99 Jesse Glick [JavaDoc] * 3 src-jtulach1.2 3/14/99 Petr Hamernik * 2 src-jtulach1.1 1/20/99 Petr Hamernik * 1 src-jtulach1.0 1/17/99 Jaroslav Tulach * $ * Beta Change History: * 0 Tuborg 0.21 --/--/98 Jan Formanek added createFromClass, getAsClass methods */